#pragma once

#include <iostream>
#include <map>
#include <vector>
#include <thread>
#include <mutex>
#include <cstring>
#include <cstdlib>
#include "udp_sock.hpp"
#include "ringQueue.hpp"

const static uint16_t portdefault = 8080;

class UdpServer
{
public:
    UdpServer(uint16_t port = portdefault) : _port(port)
    {
    }
    ~UdpServer() {}

    void Init()
    {
        _sock.Socket();
        _sock.Bind(_port);
    }

    void Start()
    {
        std::thread rv(&UdpServer::Recv, this);
        std::thread bt(&UdpServer::Broadcast, this);
        rv.join();
        bt.join();
    }

private:
    void Broadcast()
    {
        while (true)
        {
            if (_clients.empty())
            {
                continue;
            }
            // 1. 从队列中获取数据
            std::string msg;
            {
                _queue.pop(&msg);
            }
            std::cout << "Broadcast: " << msg << std::endl;
            // 2. 遍历在线用户，依次发送数据
            // 2.1 线程安全的获取用户信息
            std::vector<struct sockaddr_in> online;
            {
                std::lock_guard<std::mutex> lock(_mtxMap);
                for (auto &i : _clients)
                {
                    online.push_back(i.second);
                }
            }
            // 2.2 业务处理 -- 发送数据
            for (auto &i : online)
            {
                socklen_t len = sizeof(i);
                _sock.Send(msg, i, len);
            }
        }
    }

    void Recv()
    {
        while (true)
        {
            // 1. 接受数据
            struct sockaddr_in peer;
            memset(&peer, 0, sizeof(peer));
            socklen_t len = sizeof(peer);
            std::string msg;
            bool flag = _sock.Recv(&msg, &peer, &len);
            if (!flag)
            {
                continue;
            }
            // debugPrint
            std::cout << "Recv: " << msg << std::endl;

            // 2. 保存数据到循环队列中
            {
                _queue.push(msg);
            }
            // 3. 保存用户信息
            // 3.1 获取用户信息
            std::string ip = inet_ntoa(peer.sin_addr);
            uint16_t port = ntohs(peer.sin_port);
            std::string key = ip + ":" + std::to_string(port);
            // 3.2 保存用户信息 -- 存在线程安全问题
            AddClient(key, peer);
        }
    }
    void AddClient(const std::string &key, const struct sockaddr_in &peer)
    {
        std::lock_guard<std::mutex> lock(_mtxMap);
        _clients[key] = peer;
    }

private:
    UdpSock _sock;
    uint16_t _port;
    RingQueue<std::string> _queue;                      // 该循环队列是线程安全的
    std::map<std::string, struct sockaddr_in> _clients; // 该map不是线程安全的
    std::mutex _mtxMap;
};